/*
实验内容2：线程互斥
1. 临界区相关对象
初始化临界区： InitializeCriticalSection()
进入临界区：EnterCriticalSection()
退出临界区：LeaveCriticalSection()
删除临界区：DeleteCriticalSection()
2. 互斥对象
创建互斥对象：CreateMutex()
打开互斥对象：OpenMutex()
释放互斥对象：ReleaseMutex()
3. 实验要求
完成两个子线程互斥，在主线程中使用系统调用 CreateThread()创建两个子线程，在子
线程中互斥地使用全局变量 count，改变其值并输出。
提示：使用初始化临界区创建，在子线程中使用 count 之前、后分别使用进入临界区和退出
临界区，运行完毕后删除临界区。
*/


#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>

// 全局变量
int count = 0;

// 信号量和互斥对象句柄
HANDLE g_hSemaphore;
HANDLE g_hMutex;

// 子线程函数
DWORD WINAPI ThreadFunc(LPVOID lpParam) {
    int threadId = (int)(intptr_t)lpParam;
    for (int i = 0; i < 5; ++i) {
        // 等待信号量
        WaitForSingleObject(g_hSemaphore, INFINITE);

        // 进入互斥区
        WaitForSingleObject(g_hMutex, INFINITE);

        // 修改共享资源
        printf("Now in Child Thread.\n");
        printf("thread%d: ct%d\n", threadId, count);
        count += 10;

        // 退出互斥区
        ReleaseMutex(g_hMutex);

        // 释放信号量
        ReleaseSemaphore(g_hSemaphore, 1, NULL);

        Sleep(200); // 让其他线程有机会运行
    }
    return 0;
}

int main() {
    HANDLE hThread1, hThread2;
    DWORD threadId1, threadId2;

    // 创建信号量
    g_hSemaphore = CreateSemaphore(NULL, 2, 2, TEXT("MySemaphore"));
    if (g_hSemaphore == NULL) {
        printf("创建信号量失败: %d\n", GetLastError());
        return 1;
    }

    // 创建互斥对象
    g_hMutex = CreateMutex(NULL, FALSE, TEXT("MyMutex"));
    if (g_hMutex == NULL) {
        printf("创建互斥对象失败: %d\n", GetLastError());
        CloseHandle(g_hSemaphore);
        return 1;
    }

    printf("Semaphore and Mutex Created Successfully!\n");

    // 创建第一个子线程
    hThread1 = CreateThread(
        NULL,                   // 默认安全属性
        0,                      // 使用默认堆栈大小  
        ThreadFunc,             // 线程函数名称
        (LPVOID)(intptr_t)1,    // 参数传入线程函数
        0,                      // 立即运行线程 
        &threadId1);            // 返回线程标识符

    if (hThread1 == NULL) {
        printf("创建线程失败: %d\n", GetLastError());
        CloseHandle(g_hSemaphore);
        CloseHandle(g_hMutex);
        return 1;
    }

    // 创建第二个子线程
    hThread2 = CreateThread(
        NULL,                   // 默认安全属性
        0,                      // 使用默认堆栈大小  
        ThreadFunc,             // 线程函数名称
        (LPVOID)(intptr_t)2,    // 参数传入线程函数
        0,                      // 立即运行线程 
        &threadId2);            // 返回线程标识符

    if (hThread2 == NULL) {
        printf("创建线程失败: %d\n", GetLastError());
        CloseHandle(hThread1);
        CloseHandle(g_hSemaphore);
        CloseHandle(g_hMutex);
        return 1;
    }

    printf("Threads Created Successfully\n");

    // 等待所有子线程完成
    WaitForSingleObject(hThread1, INFINITE);
    WaitForSingleObject(hThread2, INFINITE);

    // 关闭线程句柄
    CloseHandle(hThread1);
    CloseHandle(hThread2);

    // 关闭信号量和互斥对象句柄
    CloseHandle(g_hSemaphore);
    CloseHandle(g_hMutex);

    printf("Final count value: %d\n", count);

    return 0;
}

